Bibiografia da Aula

Livro R4DS Wickham e Grolemund, cap 13.

Tidy explain Garrick Aden-Buie disponível em https://github.com/gadenbuie/tidyexplain

Dados Relacionais

É raro ocorrer um trabalho de análise de dados usando apenas uma tabela, pois geralmente tem-se um conjunto de dados espalhado por diversas tabelas, por este motivo para responder às questões de interesse é necessário relaciona-las. Assim, coletivamente, multiplas tabelas de dados são chamadas de dados relacionais, por que geralmente o que importa são as relações e não os conjuntos de dados individuais.

As relações são sempre definidas entre um par de tabelas. Todas as outras relações são construídas a partir de uma premissa: as relações de três ou mais tabelas são sempre uma propriedade das relações entre cada par. Em alguns casos dois elemntos de um par podem ser a mesma tabela!Isso é necessário, por exemplo, se houver uma tabela com pessoas e cada pessoa é referenciada a seus pais.

Existem três famílias de verbos para trabalhar com dados relacionais.

Pré-requisitos

Vamos explorar os dados relacionais de nycflights13 usando os verbos para duas tabelas do dplyr.

library(tidyverse)
library(nycflights13)

nycflights13

Vamos usar o pacote nycflights13 para aprender sobre dados relacionais. nycflights13 contêm quatro tibbles relacionados ao dataframe flights.

  • airlines mostra o nome completo da compania de aviação e seu código.
airlines
## # A tibble: 16 x 2
##    carrier name                       
##    <chr>   <chr>                      
##  1 9E      Endeavor Air Inc.          
##  2 AA      American Airlines Inc.     
##  3 AS      Alaska Airlines Inc.       
##  4 B6      JetBlue Airways            
##  5 DL      Delta Air Lines Inc.       
##  6 EV      ExpressJet Airlines Inc.   
##  7 F9      Frontier Airlines Inc.     
##  8 FL      AirTran Airways Corporation
##  9 HA      Hawaiian Airlines Inc.     
## 10 MQ      Envoy Air                  
## 11 OO      SkyWest Airlines Inc.      
## 12 UA      United Air Lines Inc.      
## 13 US      US Airways Inc.            
## 14 VX      Virgin America             
## 15 WN      Southwest Airlines Co.     
## 16 YV      Mesa Airlines Inc.
  • airports mostra informações sobre cada aeroporto, identificado pelo código faa:
airports
## # A tibble: 1,458 x 8
##    faa   name                       lat    lon   alt    tz dst   tzone          
##    <chr> <chr>                    <dbl>  <dbl> <dbl> <dbl> <chr> <chr>          
##  1 04G   Lansdowne Airport         41.1  -80.6  1044    -5 A     America/New_Yo~
##  2 06A   Moton Field Municipal A~  32.5  -85.7   264    -6 A     America/Chicago
##  3 06C   Schaumburg Regional       42.0  -88.1   801    -6 A     America/Chicago
##  4 06N   Randall Airport           41.4  -74.4   523    -5 A     America/New_Yo~
##  5 09J   Jekyll Island Airport     31.1  -81.4    11    -5 A     America/New_Yo~
##  6 0A9   Elizabethton Municipal ~  36.4  -82.2  1593    -5 A     America/New_Yo~
##  7 0G6   Williams County Airport   41.5  -84.5   730    -5 A     America/New_Yo~
##  8 0G7   Finger Lakes Regional A~  42.9  -76.8   492    -5 A     America/New_Yo~
##  9 0P2   Shoestring Aviation Air~  39.8  -76.6  1000    -5 U     America/New_Yo~
## 10 0S9   Jefferson County Intl     48.1 -123.    108    -8 A     America/Los_An~
## # ... with 1,448 more rows
  • planes apresenta informações sobre cada avião, identificado por seu tailnum(número da calda).
planes
## # A tibble: 3,322 x 9
##    tailnum  year type          manufacturer   model  engines seats speed engine 
##    <chr>   <int> <chr>         <chr>          <chr>    <int> <int> <int> <chr>  
##  1 N10156   2004 Fixed wing m~ EMBRAER        EMB-1~       2    55    NA Turbo-~
##  2 N102UW   1998 Fixed wing m~ AIRBUS INDUST~ A320-~       2   182    NA Turbo-~
##  3 N103US   1999 Fixed wing m~ AIRBUS INDUST~ A320-~       2   182    NA Turbo-~
##  4 N104UW   1999 Fixed wing m~ AIRBUS INDUST~ A320-~       2   182    NA Turbo-~
##  5 N10575   2002 Fixed wing m~ EMBRAER        EMB-1~       2    55    NA Turbo-~
##  6 N105UW   1999 Fixed wing m~ AIRBUS INDUST~ A320-~       2   182    NA Turbo-~
##  7 N107US   1999 Fixed wing m~ AIRBUS INDUST~ A320-~       2   182    NA Turbo-~
##  8 N108UW   1999 Fixed wing m~ AIRBUS INDUST~ A320-~       2   182    NA Turbo-~
##  9 N109UW   1999 Fixed wing m~ AIRBUS INDUST~ A320-~       2   182    NA Turbo-~
## 10 N110UW   1999 Fixed wing m~ AIRBUS INDUST~ A320-~       2   182    NA Turbo-~
## # ... with 3,312 more rows
  • weather mostra informações do clima em no aeroporto de Nova Yorque para cada hora:
weather
## # A tibble: 26,115 x 15
##    origin  year month   day  hour  temp  dewp humid wind_dir wind_speed
##    <chr>  <int> <int> <int> <int> <dbl> <dbl> <dbl>    <dbl>      <dbl>
##  1 EWR     2013     1     1     1  39.0  26.1  59.4      270      10.4 
##  2 EWR     2013     1     1     2  39.0  27.0  61.6      250       8.06
##  3 EWR     2013     1     1     3  39.0  28.0  64.4      240      11.5 
##  4 EWR     2013     1     1     4  39.9  28.0  62.2      250      12.7 
##  5 EWR     2013     1     1     5  39.0  28.0  64.4      260      12.7 
##  6 EWR     2013     1     1     6  37.9  28.0  67.2      240      11.5 
##  7 EWR     2013     1     1     7  39.0  28.0  64.4      240      15.0 
##  8 EWR     2013     1     1     8  39.9  28.0  62.2      250      10.4 
##  9 EWR     2013     1     1     9  39.9  28.0  62.2      260      15.0 
## 10 EWR     2013     1     1    10  41    28.0  59.6      260      13.8 
## # ... with 26,105 more rows, and 5 more variables: wind_gust <dbl>,
## #   precip <dbl>, pressure <dbl>, visib <dbl>, time_hour <dttm>

A partir do gráfico abaixo é possível verificar as relações entre cada tabela.

Hickham e Grolemund - Relational data

Para nycflights13:

  • flights se conectam a planes através de uma única variável, tailnum.

  • flights se conecta a airlines pela vaariável carrier

  • flights se conecta a airports de duas maneiras: pelas variáveis origin e dest

  • flights se conecta a weather através de origin (o lugar), year, month, day e hour.

Exercícios

1 - Imagine que você gostaria de traçar(aproximadamente)a rota que cada avião faz de sua origem até seu destino. Quais variáveis você precisaria usar? Quais variáveis você precisaria combinar?

2 - Me esqueci de desenhar a relação entre weather e airports. Qual e a relação e como ela deveria aparecer no diagrama mostrado anteriormente?

3 - weather contêm apenas informações dos aeroportos de origem (NYC). Se o dataframe também tivesse dados sobre todos os aeorportos dos USA, que relação adicional esta tabela teria com flights?

4 - Sabemos que alguns dias do ano são “especiais”, que menos vôos ocorrem nesses dias. Como você representaria estes dados em um data frame? Quais seriam as chaves primárias desta tabela? Como ela se conectaria com as tabela existentes?

keys

As variáveis usadas para conectar cada par de tabelas são chamadas de keys ou chaves. Uma chave é uma variável (ou conjunto de variáveis) que identifica unicamente uma observação.

Existem dois tipos de chaves:

  • Chave primária(primary key): identifica uma observação única em sua própria tabela. Por exemplo, planes$tailnum é uma chave primária porque identifica unicamente cada avião na tabela planes.

  • Foreign Key: Identifica uma observação única em outra tabela. Por exemplo, flights$tailnum é uma Foreign Key porque apareça na tabela flights onde relaciona cada vôo a a um avião único.

Uma variável também pode ser os dois tipos de chave ao mesmo tempo. Por exemplo, origin é parte da chave primária de weather e tambem é foreign key da tabela airport.

Uma vez que você tenha identificado as chaves primárias em suas tabelas, é boa prática verificar se elas realmente identificam unicamente cada observação. Podemos fazer isso com count(), contando as chaves primárias e procurando por entradas onde n é maior que um:

planes %>% 
  count(tailnum) %>% 
  filter(n > 1)
## # A tibble: 0 x 2
## # ... with 2 variables: tailnum <chr>, n <int>
weather %>% 
  count(year, month, day, hour, origin) %>% 
  filter(n > 1)
## # A tibble: 3 x 6
##    year month   day  hour origin     n
##   <int> <int> <int> <int> <chr>  <int>
## 1  2013    11     3     1 EWR        2
## 2  2013    11     3     1 JFK        2
## 3  2013    11     3     1 LGA        2

Pode acontecer de uma tabela não possuir uma chave primária explicita: cada linha é uma observação, mas nenhuma combinação de variáveis a identifica de forma confiável. Por exeplo, qual é a chave primária na tabela flights? Você pode pensar que seria a data mais o número do vôo ou tail number(número da cauda), mas nenhuma das duas é única.

flights %>% 
  count(year, month, day, flight) %>% 
  filter(n > 1)
## # A tibble: 29,768 x 5
##     year month   day flight     n
##    <int> <int> <int>  <int> <int>
##  1  2013     1     1      1     2
##  2  2013     1     1      3     2
##  3  2013     1     1      4     2
##  4  2013     1     1     11     3
##  5  2013     1     1     15     2
##  6  2013     1     1     21     2
##  7  2013     1     1     27     4
##  8  2013     1     1     31     2
##  9  2013     1     1     32     2
## 10  2013     1     1     35     2
## # ... with 29,758 more rows
flights %>% 
  count(year, month, day, tailnum) %>% 
  filter(n > 1)
## # A tibble: 64,928 x 5
##     year month   day tailnum     n
##    <int> <int> <int> <chr>   <int>
##  1  2013     1     1 N0EGMQ      2
##  2  2013     1     1 N11189      2
##  3  2013     1     1 N11536      2
##  4  2013     1     1 N11544      3
##  5  2013     1     1 N11551      2
##  6  2013     1     1 N12540      2
##  7  2013     1     1 N12567      2
##  8  2013     1     1 N13123      2
##  9  2013     1     1 N13538      3
## 10  2013     1     1 N13566      3
## # ... with 64,918 more rows

Se uma tabela não possui uma chave primária, pode ser bom criar uma com as funções mutate() e row_number(). Assim fica mais fácil relacionar observações se os dados foram filtrados é você quer verificar novamente os dados originais. Este tipo de chave é chamada de surrogate key.

Uma chave primária e sua correspondente foreign key em outra tabela formam uma realação. Relações são geralmente de um para muitos. Por exemplo,

Exercícios

1 - Faça uma chave surrogate para a tabela flights

2 - Identifique as chaves nos seguintes conjuntos de dados:

  1. Lahman::Batting,
  2. babynames::babynames
  3. nasaweather::atmos
  4. fueleconomy::vehicles
  5. ggplot2::diamonds

(talvez seja necessário instalar alguns pacotes e ler a documentação)

3 - Faça um diagrama ilustrando as conexões entre as tabelas Batting, Master, e Salaries no pacote Lahman. Faça outro diagrama que deve mostrar as relações entre Master, Managers, AwardsManagers.

Como você caracterizaria a relação entre as tabelas Batting, Pitching e Fielding.

Mutating joins

Como o mutate(), as funções join adicionam variáveis a direita, então, se houverem muitas variáveis na tabela elas não aparecerão printadas, por este motivo iremos estreitar as tabelas dos próximos exemplos, criando tabelas menos largas(com menos colunas)

flights2 <- flights %>% 
  select(year:day, hour, origin, dest, tailnum, carrier)
flights2
## # A tibble: 336,776 x 8
##     year month   day  hour origin dest  tailnum carrier
##    <int> <int> <int> <dbl> <chr>  <chr> <chr>   <chr>  
##  1  2013     1     1     5 EWR    IAH   N14228  UA     
##  2  2013     1     1     5 LGA    IAH   N24211  UA     
##  3  2013     1     1     5 JFK    MIA   N619AA  AA     
##  4  2013     1     1     5 JFK    BQN   N804JB  B6     
##  5  2013     1     1     6 LGA    ATL   N668DN  DL     
##  6  2013     1     1     5 EWR    ORD   N39463  UA     
##  7  2013     1     1     6 EWR    FLL   N516JB  B6     
##  8  2013     1     1     6 LGA    IAD   N829AS  EV     
##  9  2013     1     1     6 JFK    MCO   N593JB  B6     
## 10  2013     1     1     6 LGA    ORD   N3ALAA  AA     
## # ... with 336,766 more rows

(Lembre-se, no RStudio é possível usar _view() para evitar este tipo de problema.)

Imagine que você queira adicionar os nomes de linhas aéreas à tabela flights2. Você pode combinar as tabelas flights e Flights2 com um left_join():

flights2 %>%
  select(-origin, -dest) %>% 
  left_join(airlines, by = "carrier")
## # A tibble: 336,776 x 7
##     year month   day  hour tailnum carrier name                    
##    <int> <int> <int> <dbl> <chr>   <chr>   <chr>                   
##  1  2013     1     1     5 N14228  UA      United Air Lines Inc.   
##  2  2013     1     1     5 N24211  UA      United Air Lines Inc.   
##  3  2013     1     1     5 N619AA  AA      American Airlines Inc.  
##  4  2013     1     1     5 N804JB  B6      JetBlue Airways         
##  5  2013     1     1     6 N668DN  DL      Delta Air Lines Inc.    
##  6  2013     1     1     5 N39463  UA      United Air Lines Inc.   
##  7  2013     1     1     6 N516JB  B6      JetBlue Airways         
##  8  2013     1     1     6 N829AS  EV      ExpressJet Airlines Inc.
##  9  2013     1     1     6 N593JB  B6      JetBlue Airways         
## 10  2013     1     1     6 N3ALAA  AA      American Airlines Inc.  
## # ... with 336,766 more rows

Como resultado desta junção temos uma nova variável, name. Por este motivo chamamos este tipo de join de mutating join. Neste caso, seria possível ter o mesmo resultado usando a função mutate().

flights2 %>%
  select(-origin, -dest) %>% 
  mutate(name = airlines$name[match(carrier, airlines$carrier)])
## # A tibble: 336,776 x 7
##     year month   day  hour tailnum carrier name                    
##    <int> <int> <int> <dbl> <chr>   <chr>   <chr>                   
##  1  2013     1     1     5 N14228  UA      United Air Lines Inc.   
##  2  2013     1     1     5 N24211  UA      United Air Lines Inc.   
##  3  2013     1     1     5 N619AA  AA      American Airlines Inc.  
##  4  2013     1     1     5 N804JB  B6      JetBlue Airways         
##  5  2013     1     1     6 N668DN  DL      Delta Air Lines Inc.    
##  6  2013     1     1     5 N39463  UA      United Air Lines Inc.   
##  7  2013     1     1     6 N516JB  B6      JetBlue Airways         
##  8  2013     1     1     6 N829AS  EV      ExpressJet Airlines Inc.
##  9  2013     1     1     6 N593JB  B6      JetBlue Airways         
## 10  2013     1     1     6 N3ALAA  AA      American Airlines Inc.  
## # ... with 336,766 more rows

Entretanto, este método não é prático quando se precisa relacionar muitas variáveis, além de necessitar de uma leitura mais minunciosa para o seu entendimento.

Entendendo Joins

Será mais fácil entender como funcionam os joins com uma representação visual de seu funcionamento:

#x
#> # A tibble: 3 x 2
#>      id x    
#>   <int> <chr>
#> 1     1 x1   
#> 2     2 x2   
#> 3     3 x3
#y
#> # A tibble: 3 x 2
#>      id y    
#>   <int> <chr>
#> 1     1 y1   
#> 2     2 y2   
#> 3     4 y4

As colunas coloridas representam a variável “chave”: usadas para relacionas as linhas(observações) entre as duas tabelas. A coluna cinza representa os valores.

Um join é uma maneira de conectar cada linha em x a zero, uma ou mais linhas em Y. Será possível entender melhor este funcionamento nas tabelas animadas que serão mostradas nos próximos exemplos.

Inner Join

É o tipo mais simples de Join, relaciona pares de observações quando suas chaves são iguais.

#inner_join(x, y, by = "id")
#> # A tibble: 2 x 3
#>      id x     y    
#>   <int> <chr> <chr>
#> 1     1 x1    y1   
#> 2     2 x2    y2

As observações não relacionadas são ignoradas no output. Não se costuma usar este tipo de join em análises pois facilita a perda de observações.

Outer Joins

Preserva observações que aparecem em pelo menos uma das tabelas, existem três tipos:

  • Left join, mantem as observações de X.
  • right join, mantem as observações em y.
  • Full join, mantem as observações tanto em x quanto em y.

O join mais usado é o left join, você pode trazer dados de outra tabela preservando as observações originais.

Outra maneira de representar os joins é através de um diagrama de Venn:

  • Full join, mantem as observações tanto em x quanto em y.

Fonte: Hickham e Grolemund - Relational data

Chaves duplicadas

Até agora, em todos os diagramas assumimos que as chaves eram únicas, porém, não é sempre o caso. Agora vamos entender o que acontece quando as chaves não são únicas. Existem duas possibilidades:

1 - Uma das tabelas tem chaves duplicadas. isso acontece quando se quer adicionar informações adicionais, assim cria-se uma relação de um para muitos.

Fonte: Hickham e Grolemund - Relational data

x <- tribble(
  ~key, ~val_x,
     1, "x1",
     2, "x2",
     2, "x3",
     1, "x4"
)
y <- tribble(
  ~key, ~val_y,
     1, "y1",
     2, "y2"
)
left_join(x, y, by = "key")
## # A tibble: 4 x 3
##     key val_x val_y
##   <dbl> <chr> <chr>
## 1     1 x1    y1   
## 2     2 x2    y2   
## 3     2 x3    y2   
## 4     1 x4    y1

2 - Existem chaves duplicadas nas duas tabelas. Isto geralmente é um erro porque em nenhuma das duas tabelas as chaves identificam de forma única uma observação.

Fonte: Hickham e Grolemund - Relational data

x <- tribble(
  ~key, ~val_x,
     1, "x1",
     2, "x2",
     2, "x3",
     3, "x4"
)
y <- tribble(
  ~key, ~val_y,
     1, "y1",
     2, "y2",
     2, "y3",
     3, "y4"
)
left_join(x, y, by = "key")
## # A tibble: 6 x 3
##     key val_x val_y
##   <dbl> <chr> <chr>
## 1     1 x1    y1   
## 2     2 x2    y2   
## 3     2 x2    y3   
## 4     2 x3    y2   
## 5     2 x3    y3   
## 6     3 x4    y4

Definindo as colunas chave

Até agora, os pares de tabelas foram sempre unidas por uma única variável e essa variável tem o mesmo nome nas duas tambelas. Esta restrição foi codificada por by=“key” . É possível usar outros valores para by para conectar tabelas de outras maneiras:

  • O deafault, by=null, usa todas as variáveis que aparecem nas duas tabelas, chamado de união natural. Por exemplo, as tabelas flights e weather se relacionam em suas variáveis comuns: year, month, day, hour e origin.
flights2 %>% 
  left_join(weather)
## Joining, by = c("year", "month", "day", "hour", "origin")
## # A tibble: 336,776 x 18
##     year month   day  hour origin dest  tailnum carrier  temp  dewp humid
##    <int> <int> <int> <dbl> <chr>  <chr> <chr>   <chr>   <dbl> <dbl> <dbl>
##  1  2013     1     1     5 EWR    IAH   N14228  UA       39.0  28.0  64.4
##  2  2013     1     1     5 LGA    IAH   N24211  UA       39.9  25.0  54.8
##  3  2013     1     1     5 JFK    MIA   N619AA  AA       39.0  27.0  61.6
##  4  2013     1     1     5 JFK    BQN   N804JB  B6       39.0  27.0  61.6
##  5  2013     1     1     6 LGA    ATL   N668DN  DL       39.9  25.0  54.8
##  6  2013     1     1     5 EWR    ORD   N39463  UA       39.0  28.0  64.4
##  7  2013     1     1     6 EWR    FLL   N516JB  B6       37.9  28.0  67.2
##  8  2013     1     1     6 LGA    IAD   N829AS  EV       39.9  25.0  54.8
##  9  2013     1     1     6 JFK    MCO   N593JB  B6       37.9  27.0  64.3
## 10  2013     1     1     6 LGA    ORD   N3ALAA  AA       39.9  25.0  54.8
## # ... with 336,766 more rows, and 7 more variables: wind_dir <dbl>,
## #   wind_speed <dbl>, wind_gust <dbl>, precip <dbl>, pressure <dbl>,
## #   visib <dbl>, time_hour <dttm>
  • Um vetor caracter, by=“x”. É como um join natural, mas usa apenas algumas das variáveis comuns. Por exemplo, flights e planes tem variáveis year, mas elas tem significados diferentes então unimos as tabelas apenas por tailnum
flights2 %>% 
  left_join(planes, by = "tailnum")
## # A tibble: 336,776 x 16
##    year.x month   day  hour origin dest  tailnum carrier year.y type 
##     <int> <int> <int> <dbl> <chr>  <chr> <chr>   <chr>    <int> <chr>
##  1   2013     1     1     5 EWR    IAH   N14228  UA        1999 Fixe~
##  2   2013     1     1     5 LGA    IAH   N24211  UA        1998 Fixe~
##  3   2013     1     1     5 JFK    MIA   N619AA  AA        1990 Fixe~
##  4   2013     1     1     5 JFK    BQN   N804JB  B6        2012 Fixe~
##  5   2013     1     1     6 LGA    ATL   N668DN  DL        1991 Fixe~
##  6   2013     1     1     5 EWR    ORD   N39463  UA        2012 Fixe~
##  7   2013     1     1     6 EWR    FLL   N516JB  B6        2000 Fixe~
##  8   2013     1     1     6 LGA    IAD   N829AS  EV        1998 Fixe~
##  9   2013     1     1     6 JFK    MCO   N593JB  B6        2004 Fixe~
## 10   2013     1     1     6 LGA    ORD   N3ALAA  AA          NA <NA> 
## # ... with 336,766 more rows, and 6 more variables: manufacturer <chr>,
## #   model <chr>, engines <int>, seats <int>, speed <int>, engine <chr>
  • Um vetor caracter nomeado: by = c(“a” = “b”) . Isso vai relacionar a variável a na tabela x a uma variável b na tabela y.

Por exemplo, se quisermos desenhar um mapa precisamos combinar os dados de flights e airports que contem a localização de cada aeroporto. Cada vôo tem uma origem e um destino airport, então precisamos especificar qual queremos unir a qual.

flights2 %>% 
  left_join(airports, c("dest" = "faa"))
## # A tibble: 336,776 x 15
##     year month   day  hour origin dest  tailnum carrier name    lat   lon   alt
##    <int> <int> <int> <dbl> <chr>  <chr> <chr>   <chr>   <chr> <dbl> <dbl> <dbl>
##  1  2013     1     1     5 EWR    IAH   N14228  UA      Geor~  30.0 -95.3    97
##  2  2013     1     1     5 LGA    IAH   N24211  UA      Geor~  30.0 -95.3    97
##  3  2013     1     1     5 JFK    MIA   N619AA  AA      Miam~  25.8 -80.3     8
##  4  2013     1     1     5 JFK    BQN   N804JB  B6      <NA>   NA    NA      NA
##  5  2013     1     1     6 LGA    ATL   N668DN  DL      Hart~  33.6 -84.4  1026
##  6  2013     1     1     5 EWR    ORD   N39463  UA      Chic~  42.0 -87.9   668
##  7  2013     1     1     6 EWR    FLL   N516JB  B6      Fort~  26.1 -80.2     9
##  8  2013     1     1     6 LGA    IAD   N829AS  EV      Wash~  38.9 -77.5   313
##  9  2013     1     1     6 JFK    MCO   N593JB  B6      Orla~  28.4 -81.3    96
## 10  2013     1     1     6 LGA    ORD   N3ALAA  AA      Chic~  42.0 -87.9   668
## # ... with 336,766 more rows, and 3 more variables: tz <dbl>, dst <chr>,
## #   tzone <chr>
flights2 %>% 
  left_join(airports, c("origin" = "faa"))
## # A tibble: 336,776 x 15
##     year month   day  hour origin dest  tailnum carrier name    lat   lon   alt
##    <int> <int> <int> <dbl> <chr>  <chr> <chr>   <chr>   <chr> <dbl> <dbl> <dbl>
##  1  2013     1     1     5 EWR    IAH   N14228  UA      Newa~  40.7 -74.2    18
##  2  2013     1     1     5 LGA    IAH   N24211  UA      La G~  40.8 -73.9    22
##  3  2013     1     1     5 JFK    MIA   N619AA  AA      John~  40.6 -73.8    13
##  4  2013     1     1     5 JFK    BQN   N804JB  B6      John~  40.6 -73.8    13
##  5  2013     1     1     6 LGA    ATL   N668DN  DL      La G~  40.8 -73.9    22
##  6  2013     1     1     5 EWR    ORD   N39463  UA      Newa~  40.7 -74.2    18
##  7  2013     1     1     6 EWR    FLL   N516JB  B6      Newa~  40.7 -74.2    18
##  8  2013     1     1     6 LGA    IAD   N829AS  EV      La G~  40.8 -73.9    22
##  9  2013     1     1     6 JFK    MCO   N593JB  B6      John~  40.6 -73.8    13
## 10  2013     1     1     6 LGA    ORD   N3ALAA  AA      La G~  40.8 -73.9    22
## # ... with 336,766 more rows, and 3 more variables: tz <dbl>, dst <chr>,
## #   tzone <chr>

Exercícios

1 - Compute o atraso médio por destino, então una aos dados da tabela airports, assim você poderá mostrar a distribuição espacial dos atrasos. Aqui esta um modo fácil de plotar um mapa dos estados unidos.

airports %>%
  semi_join(flights, c("faa" = "dest")) %>%
  ggplot(aes(lon, lat)) +
    borders("state") +
    geom_point() +
    coord_quickmap()

Voce talvez queira usar size ou color dos pontos para mostrar o atraso médio em cada aeroporto.

2 - Adicione a localização da origem e do destino a tabela flights

3 - Existe relação entre a idade do avião e seus atrasos?

4 - Que condições climáticas influenciam nos atrasos?

5 -O que aconteceu em 13 de junho de 2013? Mostre o padrão espacial de atrasos, use o google para fazer uma referência crusada com o clima no dia.

Filtering Joins

Filtering joins relacionam observações do mesmo modo que muatating joins, mas afetam as observações, não as variáveis. Existem 2 tipos.

  • semi_join(x,y) mantêm todas as orbservações em x que tenham uma correspondência em y.
#semi_join(x, y, by = "id")
#> # A tibble: 2 x 2
#>      id x    
#>   <int> <chr>
#> 1     1 x1   
#> 2     2 x2
  • anti_join(x,y) Ignora todas as observações em x que tenham correspondência em y.
#anti_join(x, y, by = "id")
#> # A tibble: 1 x 2
#>      id x    
#>   <int> <chr>
#> 1     3 x3

Semi-joins são úteis ao relacionar tabelas de sumário filtradas de volta para as linhas originais. Por exemplo, imagine que você encontrou os 10 destinos mais populares:

top_dest <- flights %>%
  count(dest, sort = TRUE) %>%
  head(10)
top_dest
## # A tibble: 10 x 2
##    dest      n
##    <chr> <int>
##  1 ORD   17283
##  2 ATL   17215
##  3 LAX   16174
##  4 BOS   15508
##  5 MCO   14082
##  6 CLT   14064
##  7 SFO   13331
##  8 FLL   12055
##  9 MIA   11728
## 10 DCA    9705

Agora você quer encontrar cada vôo que foi para cada um destes destinos. Você poderia fazer um filtro:

flights %>% 
  filter(dest %in% top_dest$dest)
## # A tibble: 141,145 x 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      542            540         2      923            850
##  2  2013     1     1      554            600        -6      812            837
##  3  2013     1     1      554            558        -4      740            728
##  4  2013     1     1      555            600        -5      913            854
##  5  2013     1     1      557            600        -3      838            846
##  6  2013     1     1      558            600        -2      753            745
##  7  2013     1     1      558            600        -2      924            917
##  8  2013     1     1      558            600        -2      923            937
##  9  2013     1     1      559            559         0      702            706
## 10  2013     1     1      600            600         0      851            858
## # ... with 141,135 more rows, and 11 more variables: arr_delay <dbl>,
## #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

Mas é difícil fazer o mesmo para múltiplas variáveis. Por exemplo, imagine que você encontrou os 10 dias com maiores atrasos médios. Como você construiria um filtro que usasse year, month e day para relacionar a de volta a tabela flights?

Ao invés disso você pode usar um semi-join, que conecta as duas tabelas como um mutating join, mas ao invés de adicionar novas colunas, mantem apenas as colunas de x que tem uma correspondência em y.

y

flights %>% 
  semi_join(top_dest)
## Joining, by = "dest"
## # A tibble: 141,145 x 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      542            540         2      923            850
##  2  2013     1     1      554            600        -6      812            837
##  3  2013     1     1      554            558        -4      740            728
##  4  2013     1     1      555            600        -5      913            854
##  5  2013     1     1      557            600        -3      838            846
##  6  2013     1     1      558            600        -2      753            745
##  7  2013     1     1      558            600        -2      924            917
##  8  2013     1     1      558            600        -2      923            937
##  9  2013     1     1      559            559         0      702            706
## 10  2013     1     1      600            600         0      851            858
## # ... with 141,135 more rows, and 11 more variables: arr_delay <dbl>,
## #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

Anti-joins são úteis na identificação de falta de correspondência. Por exemplo, conectando flights e planes você pode se interessar em saber que existem muitos vôos que não tem correspondência em planes.

flights %>%
  anti_join(planes, by = "tailnum") %>%
  count(tailnum, sort = TRUE)
## # A tibble: 722 x 2
##    tailnum     n
##    <chr>   <int>
##  1 <NA>     2512
##  2 N725MQ    575
##  3 N722MQ    513
##  4 N723MQ    507
##  5 N713MQ    483
##  6 N735MQ    396
##  7 N0EGMQ    371
##  8 N534MQ    364
##  9 N542MQ    363
## 10 N531MQ    349
## # ... with 712 more rows

Execícios

1 - Qual o siginificado de um vôo ter um tailnum faltante? O que os tail numbers que não tem uma correspondência em planes tem em comum?(dica: uma variável explica ~90% dos problemas.)

2 - Filtre flights para mostrar mostrar apenas os vôos com aviões que tenham feito pelo menos 100 vôos.

3 - Combine fueleconomy::vehicles e fueleconomy::common para encontrar apenas os registros dos modelos mais comuns.

4 - Encontre as 48 horas( no decorrer de um ano inteiro) que tem os piores atrasos. Faça a referência cruzada com os dados de weather. Consegue ver os padrões?

5 - O que anti_join(flights, airports, by = c(“dest” = “faa”)) te diz? O que anti_join(airports, flights, by = c(“faa” = “dest”)) te diz?

6 - Você pode esperar que haja uma relação implicita entre avião e linha aerea, poque cada avião voa por uma unica linha aerea. Confirme ou rejeite esta hipótese usando as ferramentas que você aprendeu até agora.

Problemas com Join

Os dados com que temos trabalhado ate agora foram preparados para que você tivesse a menor quantidade possível de problemas até agora. Seus próprios dados ou tabelas provavelmente não vão estar do mesmo modo, então aqui vão algumas dicas que você deve aplicar a suas próprias tabelas para fazer com que seus joins funcionem perfeitamente.

1 - Comece identificando as variáveis que formam as chaves primárias em cada tabela. Você normalmente deve fazer isso baseado em seus conhecimentos sobre os dados, não empiricamente olhando combinaçoes de dados que dão um identificador único. Se você olhar para as variáveis sem pensar em seu significado, talvez não dê sorte e encontre combinações que são únicas em sua tabela mas a relação não é verdadeira em geral.

Por exemplo, a altitude e a longitude identifica unicamente cada aeroporto mão não são bons identificadores.

airports %>% count(alt, lon) %>% filter(n > 1)
## # A tibble: 0 x 3
## # ... with 3 variables: alt <dbl>, lon <dbl>, n <int>

2 - Verifique se nenhuma das variáveis na chave primária está faltando. Se algum valor estiver faltando não há como identificar uma observação.

3 - Verifique se suas foreign keys correspondem chaves primárias em outra tabela. O melhor modo de fazer isso é com um anti_join() . è comum que chaves não tenham correspondência por conta de erros de entrada.

Se você tem chaves faltantes, você analisar de forma cuidadosa o uso de inner joins vs. outer joins, considerando cuidadosamente se você quer ou não linhas que não tem correspondência.

Tenha conciência de que apenas checar o número de colunas antes e depois dos joins não é o suficiente para assegurar que o join deu certo. Se você tiver um inner join com chaves duplicadas em ambas as tabelas, você pode não dar sorte e o número de linhas descartadas ser igual ao número de linhas iguais.

Set operations

São úteis quando se quer quebrar um filtro mais complexo em partes menores. Todas estas operações funcionam com uma linha completa, comparando o valor de cada variável. Elas esperam que as entradas de x e y tenham a mesma variável, e tratam as observações como conjuntos:

#x
#> # A tibble: 3 x 2
#>   x     y    
#>   <chr> <chr>
#> 1 1     a    
#> 2 1     b    
#> 3 2     a
#y 
#> # A tibble: 2 x 2
#>   x     y    
#>   <chr> <chr>
#> 1 1     a    
#> 2 2     b
  • intersect(x, y): retorna apenas observações presentes em x e y
#intersect(x, y)
#> # A tibble: 1 x 2
#>   x     y    
#>   <chr> <chr>
#> 1 1     a
  • union(x, y): Retorna observações únicas em x e y.
#union(x, y)
#> # A tibble: 4 x 2
#>   x     y    
#>   <chr> <chr>
#> 1 2     b    
#> 2 2     a    
#> 3 1     b    
#> 4 1     a
  • Union_All(x,y) - Todas as linhas de x e y mantem as observações duplicadas.
#union_all(x, y)
#> # A tibble: 5 x 2
#>   x     y    
#>   <chr> <chr>
#> 1 1     a    
#> 2 1     b    
#> 3 2     a    
#> 4 1     a    
#> 5 2     b
  • setdiff(x,y) - Retorna as observações em x maas não em y.
#setdiff(x, y)
#> # A tibble: 2 x 2
#>   x     y    
#>   <chr> <chr>
#> 1 1     b    
#> 2 2     a